#!/usr/bin/python
# -*- coding: utf-8 -*-
import threading
import json
import time
import datetime
import logging
import logging.handlers
import subprocess
import os


################################# Worker start ###########################

class Worker(threading.Thread):
    '''
    @params lock 锁
    @params threadName 进程名
    @params conf_file 配置文件路径
    @desc init
    '''

    def __init__(self, lock, threadName, conf_file):
        super(Worker, self).__init__()  # 一定要显式的调用父类的初始化函数
        self.conf_file = conf_file
        self.lock = lock
        # 默认日志记录基础路径 - 不存在则创建
        self.makeLogsPath()
        self.loop_sign = 'loop'  # 间隔时间标识符
        self.day_sign = 'day'  # 每天标识符
        self.week_sign = 'week'  # 周标识符
        # self.week_list = ['mon', 'tues', 'wed', 'thur', 'fri', 'sat', 'sun']
        # # 一周数组

    '''
    @desc run
    '''

    def run(self):
        # 判断json配置文件的修改时间是否 ≥ (当前时间 -
        # 10秒)，如果是证明任务只执行过程中，json配置文件被改动，需要热更新定时任务配置
        t = os.path.getmtime(self.conf_file)

        # if t >= (time.time() - 10):
        self.loadConfig()
        if self.conf_data != '':
            conf_data = self.conf_data
            for key in conf_data:
                log_file_path = self.log_base_file_path + key + '.log'  # 日志路径
                command = conf_data[key]['cmd']  # 执行命令
                command_time = conf_data[key]['time']  # 执行时间
                self.runCommand(log_file_path, command, command_time)

    '''
	@params log_file_path 日志路径
	@params command 执行命令
	@params command_time 执行时间
	@desc 每天执行
	'''

    def runCommand(self, log_file_path, command, command_time):

        time_list = command_time.split('/')
        time_point = time_list[0]  # 执行时间点
        time_sign = time_list[1]  # 执行时间标识

        if time_sign == '':
            return
        # 循环
        if time_sign == self.loop_sign:
            self.runLoop(time_point, log_file_path, command)
        # 每天
        elif time_sign == self.day_sign:
            self.runDay(time_point, log_file_path, command)
        # 每周
        elif time_sign.find(self.week_sign) != -1:
            self.runWeek(time_point, time_sign, log_file_path, command)

    '''
    @params 
	@desc 间隔时间执行
    '''

    def runLoop(self, time_point, log_file_path, command):
        time_point = int(time_point)
        current_milli_time = self.getCurrentTime()
        # 时间间隔执行 每隔 time_point 秒执行一次
        if current_milli_time % int(time_point) == 0:
            command_obj = Command(log_file_path, command)
            command_obj.start()

    '''
	@params 
	@desc 每天指定时间执行
	'''

    def runDay(self, time_point, log_file_path, command):
        command_time_str = str(datetime.date.today()) + \
            ' ' + str(time_point)  # 拼接当前日期
        command_time_array = time.strptime(
            command_time_str, "%Y-%m-%d %H:%M:%S")
        command_time_stamp = int(time.mktime(command_time_array))
        current_milli_time = self.getCurrentTime()
        if command_time_stamp == current_milli_time:
            command_obj = Command(log_file_path, command)
            command_obj.start()

    '''
	@desc 每个礼拜指定时间执行
	'''

    def runWeek(self, time_point, time_sign, log_file_path, command):
        week_list = time_sign.split('_')
        week_command_day = int(week_list[1])
        current_week_day = self.getCurrentWeek()
        if week_command_day == current_week_day:
            self.runDay(time_point, log_file_path, command)

    '''
    @desc 本周第几天 0 - 周日
    '''

    def getCurrentWeek(self):
        dtime = datetime.datetime.now()
        current_week_day = int(dtime.weekday())
        return current_week_day + 1

    '''
    @desc 当前时间戳
    '''

    def getCurrentTime(self):
        dtime = datetime.datetime.now()
        current_milli_time = int(time.mktime(dtime.timetuple()))
        return current_milli_time

    '''
	@params 
	@desc 加载配置文件
	'''

    def loadConfig(self):
        self.lock.acquire()  # 锁
        file_object = open(self.conf_file, 'r')
        json_str = ''
        try:
            json_str = file_object.read()
        finally:
            file_object.close()

        if json_str == '':
            return
        self.conf_data = json.loads(json_str)

        self.lock.release()  # 解锁

    '''
    @desc 创建目录 - 每天创建一个
    '''

    def makeLogsPath(self):
        current_cwd = os.getcwd()
        log_base_file_path = current_cwd + '/logs/'
        localtime = time.strftime(
            '%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
        ymd_path = time.strftime('%Y%m%d', time.localtime(time.time()))
        self.log_base_file_path = str(log_base_file_path) + str(ymd_path) + '/'
        if not os.path.isdir(self.log_base_file_path):
            os.makedirs(self.log_base_file_path)
        return


################################# Worker end ###########################


################################# Command start ##########################

class Command(threading.Thread):

    def __init__(self, log_file_path, command):
        super(Command, self).__init__()  # 一定要显式的调用父类的初始化函数。
        self.log_file_path = log_file_path
        self.command = command

    def run(self):
        # output = subprocess.check_output(self.command)  # 执行命令
        output = os.popen(self.command).read()
        self.writeLog(self.log_file_path, output)

    '''
	@params log_file_path 日志路径
	@params message 日志信息
	@desc 记录日志
	'''

    def writeLog(self, log_file_path, message):
        handler = logging.handlers.RotatingFileHandler(
            log_file_path, maxBytes=1024 * 1024, backupCount=5)  # 实例化handler
        fmt = '%(asctime)s - %(filename)s:%(lineno)s - %(name)s - %(message)s'  # 日期格式
        formatter = logging.Formatter(fmt)  # 实例化formatter
        handler.setFormatter(formatter)  # 为handler添加formatter
        logger = logging.getLogger('log')  # 获取名为tst的logger
        logger.addHandler(handler)  # 为logger添加handler
        logger.setLevel(logging.DEBUG)
        # logger.info(message)
        logger.debug(message)
        return


################################# Command end ##########################

threadName = 'Worker'
conf_file = './cmd.json'
lock = threading.RLock()

worker = Worker(lock, threadName, conf_file)
worker.start()
